<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.0">
<meta name="google-site-verification" content="SByO7HWUKwufO-witstBrFt-yyK6q3tUlCyYwkvYPiQ" />
<meta name="baidu-site-verification" content="orhaMjPwcS" />
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">

<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic|Roboto Slab:300,300italic,400,400italic,700,700italic|Roboto Mono:300,300italic,400,400italic,700,700italic&display=swap&subset=latin,latin-ext">
<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"lixiyan4633.gitee.io","root":"/","scheme":"Pisces","version":"7.7.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":"mac"},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":true,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="Apache Calcite 是一款开源SQL解析工具，我们将通过一系列的教程来了解calcite的知识">
<meta property="og:type" content="article">
<meta property="og:title" content="calcite教程02-calcite的快速入门">
<meta property="og:url" content="https://lixiyan4633.gitee.io/2020/03/18/calcite%E6%95%99%E7%A8%8B02-calcite%E7%9A%84%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/index.html">
<meta property="og:site_name" content="喜延的个人博客">
<meta property="og:description" content="Apache Calcite 是一款开源SQL解析工具，我们将通过一系列的教程来了解calcite的知识">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2020-03-18T09:56:55.000Z">
<meta property="article:modified_time" content="2020-03-18T13:28:43.981Z">
<meta property="article:author" content="李喜延">
<meta property="article:tag" content="calcite">
<meta property="article:tag" content="SQL">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://lixiyan4633.gitee.io/2020/03/18/calcite%E6%95%99%E7%A8%8B02-calcite%E7%9A%84%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true
  };
</script>

  <title>calcite教程02-calcite的快速入门 | 喜延的个人博客</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <div>
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">喜延的个人博客</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
        <p class="site-subtitle">我的大数据的之路</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>


<nav class="site-nav">
  
  <ul id="menu" class="menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-fw fa-home"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-fw fa-tags"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-fw fa-th"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-fw fa-archive"></i>归档</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-fw fa-user"></i>关于</a>

  </li>
  </ul>

</nav>
</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content">
            

  <div class="posts-expand">
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block " lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://lixiyan4633.gitee.io/2020/03/18/calcite%E6%95%99%E7%A8%8B02-calcite%E7%9A%84%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="https://tva1.sinaimg.cn/large/00831rSTly1gcyel996b4j30oa0oc1kx.jpg">
      <meta itemprop="name" content="李喜延">
      <meta itemprop="description" content="愿世界和平">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="喜延的个人博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          calcite教程02-calcite的快速入门
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              

              <time title="创建时间：2020-03-18 17:56:55 / 修改时间：21:28:43" itemprop="dateCreated datePublished" datetime="2020-03-18T17:56:55+08:00">2020-03-18</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/calcite/" itemprop="url" rel="index"><span itemprop="name">calcite</span></a>
                </span>
            </span>

          
            <div class="post-description">Apache Calcite 是一款开源SQL解析工具，我们将通过一系列的教程来了解calcite的知识<br> <img src="https://tva1.sinaimg.cn/large/00831rSTly1gcyeha1945j30re06imxs.jpg"/></div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <p>上篇是calcite的基础篇，这篇介绍calcite的快速入门帮助我们理解calcite是如何工作的。</p>
<p>本章主要介绍一个简单的CSV适配器如何一步一步的创建和连接到calcite的，这个适配器将一个目录下面csv文件表现成包含各种表的schema信息，calcite已经实现了rest接口，也提供了一整套SQL接口。</p>
<p>Calcite-Example- CSV是一个完整功能的适配器，它能够使得calcite读取csv的文件内容，值得注意的是，几百行代码就可以实现完整的SQL查询功能。</p>
<p>CSV主要包含几个重要的概念：</p>
<ul>
<li>通过Schema Factory和Schema接口实现自定义的schema</li>
<li>使用json文件描述schema</li>
<li>使用json文件描述视图view</li>
<li>通过接口定义表</li>
<li>确定表的记录类型</li>
<li>创建一个表的简单方法是，使用scannableTable接口直接列举所有行</li>
<li>创建一个表的更高级的方法是，使用FilterTable接口，并根据简单的规则进行过滤</li>
<li>创建一个表的更高级的方法是，使用TranslateTable接口，这个类能使规划规则转换成关系操作符</li>
</ul>
<h2 id="下载安装"><a href="#下载安装" class="headerlink" title="下载安装"></a>下载安装</h2><p>环境要求：java版本（&gt;=8）</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> git <span class="built_in">clone</span> https://github.com/apache/calcite.git</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">cd</span> calcite</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> mvn install -DskipTests -Dcheckstyle.skip=<span class="literal">true</span></span></span><br><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">cd</span> example/csv</span></span><br></pre></td></tr></table></figure>

<h2 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h2><p>我们需要使用sqline来连接calcite,这个工程包括SQL shell脚本。</p>
<p>继续执行下面的命令</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">./sqlline</span><br><span class="line"><span class="meta">sqlline&gt;</span><span class="bash"> !connect jdbc:calcite:model=target/<span class="built_in">test</span>-classes/model.json admin admin</span></span><br></pre></td></tr></table></figure>

<p>执行元数据查询：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">sqlline&gt; !tables</span><br><span class="line">+------------+--------------+-------------+---------------+----------+------+</span><br><span class="line">| TABLE_CAT  | TABLE_SCHEM  | TABLE_NAME  |  TABLE_TYPE   | REMARKS  | TYPE |</span><br><span class="line">+------------+--------------+-------------+---------------+----------+------+</span><br><span class="line">| null       | SALES        | DEPTS       | TABLE         | null     | null |</span><br><span class="line">| null       | SALES        | EMPS        | TABLE         | null     | null |</span><br><span class="line">| null       | SALES        | HOBBIES     | TABLE         | null     | null |</span><br><span class="line">| null       | metadata     | COLUMNS     | SYSTEM_TABLE  | null     | null |</span><br><span class="line">| null       | metadata     | TABLES      | SYSTEM_TABLE  | null     | null |</span><br><span class="line">+------------+--------------+-------------+---------------+----------+------+</span><br></pre></td></tr></table></figure>

<p>(温馨提示：在执行!table其实是在后台执行【DatabaseMetaData,getTables】)</p>
<p>现在可以看到系统有5张表，分别是EMPS，DEPTS在当前的SALES的schema中，并且COLUMNS和TABLES是系统，meta的schema中，系统表始终存在在calcite中，但是其他的是由特定的schema实现的，例如EMPSHEDEPTS,是基于target/test-classes下的 EMP.CSv和DEPTS.csv来决定的</p>
<p>在这些表的基础上，我们做一些简单的查询教程：</p>
<h2 id="模式发现："><a href="#模式发现：" class="headerlink" title="模式发现："></a>模式发现：</h2><p>现在你可能会疑惑，calcite是如何找到这些表的，这和CSV的内容是无关的，你可以理解为calcite是一个不包含存储层的一个数据库，calcite之所以能够读到信息，是因为我们执行了calcite-example-csv项目中的代码。</p>
<p>整个执行链中有很多步骤，首先，我们基于model文件中定义的schema工厂类定义了一个schema,然后，schema工厂创建了一个schema,并且这个schema创建了多张表，每张表都清楚的扫描csv文件来获取数据，最后，calcite解析了查询语句并且创建了执行计划来使用这些表来执行查询时，calcite利用表来读取数据，下面举出更详细的过程。</p>
<p>在JDBC连接字符串上，我们给出了JSON格式的模型路径，模型model.js如下：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  version: '1.0',</span><br><span class="line">  defaultSchema: 'SALES',</span><br><span class="line">  schemas: [</span><br><span class="line">    &#123;</span><br><span class="line">      name: 'SALES',</span><br><span class="line">      type: 'custom',</span><br><span class="line">      factory: 'org.apache.calcite.adapter.csv.CsvSchemaFactory',</span><br><span class="line">      operand: &#123;</span><br><span class="line">        directory: 'target/test-classes/sales'</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上面定义的模式定义一个叫SALES的单模式，这个是由schema是由<a href="https://github.com/apache/calcite/blob/master/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvSchemaFactory.java" target="_blank" rel="noopener">org.apache.calcite.adapter.csv.CsvSchemaFactory</a>插件类提供，这个插件类是由calcite-example-csv项目的一部分并且实现了SchemaFactory接口，它的create方法实例化一个模式，从模型文件传入目录参数：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> Schema <span class="title">create</span><span class="params">(SchemaPlus parentSchema, String name,</span></span></span><br><span class="line"><span class="function"><span class="params">    Map&lt;String, Object&gt; operand)</span> </span>&#123;</span><br><span class="line">  String directory = (String) operand.get(<span class="string">"directory"</span>);</span><br><span class="line">  String flavorName = (String) operand.get(<span class="string">"flavor"</span>);</span><br><span class="line">  CsvTable.Flavor flavor;</span><br><span class="line">  <span class="keyword">if</span> (flavorName == <span class="keyword">null</span>) &#123;</span><br><span class="line">    flavor = CsvTable.Flavor.SCANNABLE;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    flavor = CsvTable.Flavor.valueOf(flavorName.toUpperCase());</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> CsvSchema(</span><br><span class="line">      <span class="keyword">new</span> File(directory),</span><br><span class="line">      flavor);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在该模式的驱动下，模式工厂实例化一个名为SALES的模式，该模式是<a href="https://github.com/apache/calcite/blob/master/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvSchema.java" target="_blank" rel="noopener">org.apache.calcite.adapter.csv.CsvSchema</a>，的一个实例，并且实现了calcite接口的Schema.</p>
<p>schema的工作是提供一系列的表，这些表实现了calcite的table接口，csvSchema生成CsvTable及其子类的实例的表。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CsvSchema</span> <span class="keyword">extends</span> <span class="title">AbstractSchema</span> </span>&#123;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">final</span> File directoryFile;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">final</span> CsvTable.Flavor flavor;</span><br><span class="line">  <span class="keyword">private</span> Map&lt;String, Table&gt; tableMap;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * Creates a CSV schema.</span></span><br><span class="line"><span class="comment">   *</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> directoryFile Directory that holds &#123;<span class="doctag">@code</span> .csv&#125; files</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> flavor     Whether to instantiate flavor tables that undergo</span></span><br><span class="line"><span class="comment">   *                   query optimization</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">CsvSchema</span><span class="params">(File directoryFile, CsvTable.Flavor flavor)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>();</span><br><span class="line">    <span class="keyword">this</span>.directoryFile = directoryFile;</span><br><span class="line">    <span class="keyword">this</span>.flavor = flavor;</span><br><span class="line">  &#125;</span><br><span class="line">  ...省略其他代码</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>这个<code>CsvSchema</code>的相关代码，覆盖了AbstractSchema基类的实现getTableMap()方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> Map&lt;String, Table&gt; <span class="title">getTableMap</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="comment">// Look for files in the directory ending in ".csv", ".csv.gz", ".json",</span></span><br><span class="line">  <span class="comment">// ".json.gz".</span></span><br><span class="line">  File[] files = directoryFile.listFiles(</span><br><span class="line">      <span class="keyword">new</span> FilenameFilter() &#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">accept</span><span class="params">(File dir, String name)</span> </span>&#123;</span><br><span class="line">          <span class="keyword">final</span> String nameSansGz = trim(name, <span class="string">".gz"</span>);</span><br><span class="line">          <span class="keyword">return</span> nameSansGz.endsWith(<span class="string">".csv"</span>)</span><br><span class="line">              || nameSansGz.endsWith(<span class="string">".json"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;);</span><br><span class="line">  <span class="keyword">if</span> (files == <span class="keyword">null</span>) &#123;</span><br><span class="line">    System.out.println(<span class="string">"directory "</span> + directoryFile + <span class="string">" not found"</span>);</span><br><span class="line">    files = <span class="keyword">new</span> File[<span class="number">0</span>];</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// Build a map from table name to table; each file becomes a table.</span></span><br><span class="line">  <span class="keyword">final</span> ImmutableMap.Builder&lt;String, Table&gt; builder = ImmutableMap.builder();</span><br><span class="line">  <span class="keyword">for</span> (File file : files) &#123;</span><br><span class="line">    String tableName = trim(file.getName(), <span class="string">".gz"</span>);</span><br><span class="line">    <span class="keyword">final</span> String tableNameSansJson = trimOrNull(tableName, <span class="string">".json"</span>);</span><br><span class="line">    <span class="keyword">if</span> (tableNameSansJson != <span class="keyword">null</span>) &#123;</span><br><span class="line">      JsonTable table = <span class="keyword">new</span> JsonTable(file);</span><br><span class="line">      builder.put(tableNameSansJson, table);</span><br><span class="line">      <span class="keyword">continue</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    tableName = trim(tableName, <span class="string">".csv"</span>);</span><br><span class="line">    <span class="keyword">final</span> Table table = createTable(file);</span><br><span class="line">    builder.put(tableName, table);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> builder.build();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** Creates different sub-type of table based on the "flavor" attribute. */</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> Table <span class="title">createTable</span><span class="params">(File file)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">switch</span> (flavor) &#123;</span><br><span class="line">  <span class="keyword">case</span> TRANSLATABLE:</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> CsvTranslatableTable(file, <span class="keyword">null</span>);</span><br><span class="line">  <span class="keyword">case</span> SCANNABLE:</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> CsvScannableTable(file, <span class="keyword">null</span>);</span><br><span class="line">  <span class="keyword">case</span> FILTERABLE:</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> CsvFilterableTable(file, <span class="keyword">null</span>);</span><br><span class="line">  <span class="keyword">default</span>:</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> AssertionError(<span class="string">"Unknown flavor "</span> + flavor);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Schema扫描模型文件中定义的目录，并且以csv结尾的文件创建对应的表，在这个例子中，目录是<code>target/test-classes/sales</code> 并且包含<code>EMPS.csv</code>和<code>DEPTS.csv</code>，根据这两个csv文件最终生成了<code>EMPS</code>表和<code>DEPTS</code>表。</p>
<h2 id="schemas中的Tables和views"><a href="#schemas中的Tables和views" class="headerlink" title="schemas中的Tables和views"></a>schemas中的Tables和views</h2><p>你应该关注到，我们怎样做到不需要在模型中定义任何表，但是schema本身自动创建了表，可以使用schema的table属性来定义除了自定创建的其他表。</p>
<p>当你编写一个查询语句的时候，视图看上去就像一张表</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  version: '1.0',</span><br><span class="line">  defaultSchema: 'SALES',</span><br><span class="line">  schemas: [</span><br><span class="line">    &#123;</span><br><span class="line">      name: 'SALES',</span><br><span class="line">      type: 'custom',</span><br><span class="line">      factory: 'org.apache.calcite.adapter.csv.CsvSchemaFactory',</span><br><span class="line">      operand: &#123;</span><br><span class="line">        directory: 'target/test-classes/sales'</span><br><span class="line">      &#125;,</span><br><span class="line">      tables: [</span><br><span class="line">        &#123;</span><br><span class="line">          name: 'FEMALE_EMPS',</span><br><span class="line">          type: 'view',</span><br><span class="line">          sql: 'SELECT * FROM emps WHERE gender = \'F\''</span><br><span class="line">        &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>json中通常不需要不会有太长的字符串，因此Calcite支持另一种语法。如果你的视图有一个很长的SQL语句，你可以将它拆成几行而不是一个完整的字符串：</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  name: 'FEMALE_EMPS',</span><br><span class="line">  type: 'view',</span><br><span class="line">  sql: [</span><br><span class="line">    'SELECT * FROM emps',</span><br><span class="line">    'WHERE gender = \'F\''</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这是一个常规的schema,并且包含了一个由<a href="https://github.com/apache/calcite/blob/master/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTableFactory.java" target="_blank" rel="noopener">org.apache.calcite.adapter.csv.CsvTableFactory</a>支持的自定义表,它实现了Calcite的接口<a href="http://calcite.apache.org/apidocs/org/apache/calcite/schema/TableFactory.html" target="_blank" rel="noopener">TableFactory</a> ，它的<code>create</code>方法实例化一个<code>CsvScannableTable</code>，传入来自模型文件的<code>file</code>参数</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> CsvTable <span class="title">create</span><span class="params">(SchemaPlus schema, String name,</span></span></span><br><span class="line"><span class="function"><span class="params">    Map&lt;String, Object&gt; map, RelDataType rowType)</span> </span>&#123;</span><br><span class="line">  String fileName = (String) map.get(<span class="string">"file"</span>);</span><br><span class="line">  <span class="keyword">final</span> File file = <span class="keyword">new</span> File(fileName);</span><br><span class="line">  <span class="keyword">final</span> RelProtoDataType protoRowType =</span><br><span class="line">      rowType != <span class="keyword">null</span> ? RelDataTypeImpl.proto(rowType) : <span class="keyword">null</span>;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> CsvScannableTable(file, protoRowType);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>实现自定义表，通常是自定义模式的更简单的替代方法，两种方法最终都可能创建了一个类似table的接口，但是对于自定义来说，你不需要实现元数据发现，<code>CsvTableFactory</code>创建了一个<code>CsvScannableTable</code>，就像<code>CsvSchema</code>一样，但是表的实现过程中没有扫描文件系统去找<code>csv</code>文件。</p>
<p>自定义表需要model编写人员做更多的工作，编写人员也就有了自主权，给每个表添加不同的参数。</p>
<h2 id="执行计划优化查询"><a href="#执行计划优化查询" class="headerlink" title="执行计划优化查询"></a>执行计划优化查询</h2><p>到目前为止，只要表中没有大量数据，我们看到表的实现没有任何问题，但是，如果自定义的表有几百或者上百万的行，这就希望calcite与适配器协商进行优化。</p>
<p>这种协商是一种简单的优化，calcite通过支持添加查询计划规则有优化查询,优化器规则通过在查询分析树中查找模式来操作，并用已经实现的实现优化的新的一组节点来替换书中的匹配节点。</p>
<p>定义规则可以影响优化，例如下面的例子</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">sqlline&gt;</span><span class="bash"> !connect jdbc:calcite:model=target/<span class="built_in">test</span>-classes/model.json admin admin</span></span><br><span class="line"><span class="meta">sqlline&gt;</span><span class="bash"> explain plan <span class="keyword">for</span> select name from emps;</span></span><br><span class="line">+-----------------------------------------------------+</span><br><span class="line">| PLAN                                                |</span><br><span class="line">+-----------------------------------------------------+</span><br><span class="line">| EnumerableCalcRel(expr#0..9=[&#123;inputs&#125;], NAME=[$t1]) |</span><br><span class="line">|   EnumerableTableScan(table=[[SALES, EMPS]])        |</span><br><span class="line">+-----------------------------------------------------+</span><br><span class="line"><span class="meta">sqlline&gt;</span><span class="bash"> !connect jdbc:calcite:model=target/<span class="built_in">test</span>-classes/smart.json admin admin</span></span><br><span class="line"><span class="meta">sqlline&gt;</span><span class="bash"> explain plan <span class="keyword">for</span> select name from emps;</span></span><br><span class="line">+-----------------------------------------------------+</span><br><span class="line">| PLAN                                                |</span><br><span class="line">+-----------------------------------------------------+</span><br><span class="line">| EnumerableCalcRel(expr#0..9=[&#123;inputs&#125;], NAME=[$t1]) |</span><br><span class="line">|   CsvTableScan(table=[[SALES, EMPS]])               |</span><br><span class="line">+-----------------------------------------------------+</span><br></pre></td></tr></table></figure>

<p>很明显两个执行计划是不同的，为什么会导致这种情况呢，主要是model文件的不同，在<code>smart.json</code>中有一行</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">flavor:</span> <span class="string">"TRANSLATABLE"</span></span><br></pre></td></tr></table></figure>

<p>这一行会导致创建一个<code>CsvSchema</code>，并且他的<code>createTable</code>方法创建的是<a href="https://github.com/apache/calcite/blob/master/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTranslatableTable.java" target="_blank" rel="noopener">CsvTranslatableTable</a>而不是<code>CsvScannableTable</code>。</p>
<p><code>CsvTranslatableTable</code>实现了<a href="http://calcite.apache.org/apidocs/org/apache/calcite/schema/TranslatableTable.html#toRel()" target="_blank" rel="noopener">TranslatableTable.toRel()</a>方法来创建<a href="https://github.com/apache/calcite/blob/master/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTableScan.java" target="_blank" rel="noopener">CsvTableScan</a>。扫描其实是扫描运算符的叶子，通常实现是<a href="http://calcite.apache.org/apidocs/org/apache/calcite/adapter/enumerable/EnumerableTableScan.html" target="_blank" rel="noopener">EnumerableTableScan</a>，但是我们已经创建了一个独特的子类型来引发规则的触发.</p>
<p>下面是整个的规则：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CsvProjectTableScanRule</span> <span class="keyword">extends</span> <span class="title">RelOptRule</span> </span>&#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> CsvProjectTableScanRule INSTANCE =</span><br><span class="line">      <span class="keyword">new</span> CsvProjectTableScanRule();</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="title">CsvProjectTableScanRule</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(</span><br><span class="line">        operand(Project<span class="class">.<span class="keyword">class</span>,</span></span><br><span class="line"><span class="class">            <span class="title">operand</span>(<span class="title">CsvTableScan</span>.<span class="title">class</span>, <span class="title">none</span>())),</span></span><br><span class="line">        "CsvProjectTableScanRule");</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="meta">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onMatch</span><span class="params">(RelOptRuleCall call)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">final</span> Project project = call.rel(<span class="number">0</span>);</span><br><span class="line">    <span class="keyword">final</span> CsvTableScan scan = call.rel(<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">int</span>[] fields = getProjectFields(project.getProjects());</span><br><span class="line">    <span class="keyword">if</span> (fields == <span class="keyword">null</span>) &#123;</span><br><span class="line">      <span class="comment">// Project contains expressions more complex than just field references.</span></span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    call.transformTo(</span><br><span class="line">        <span class="keyword">new</span> CsvTableScan(</span><br><span class="line">            scan.getCluster(),</span><br><span class="line">            scan.getTable(),</span><br><span class="line">            scan.csvTable,</span><br><span class="line">            fields));</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">int</span>[] getProjectFields(List&lt;RexNode&gt; exps) &#123;</span><br><span class="line">    <span class="keyword">final</span> <span class="keyword">int</span>[] fields = <span class="keyword">new</span> <span class="keyword">int</span>[exps.size()];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; exps.size(); i++) &#123;</span><br><span class="line">      <span class="keyword">final</span> RexNode exp = exps.get(i);</span><br><span class="line">      <span class="keyword">if</span> (exp <span class="keyword">instanceof</span> RexInputRef) &#123;</span><br><span class="line">        fields[i] = ((RexInputRef) exp).getIndex();</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>; <span class="comment">// not a simple projection</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> fields;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p> 构造函数声明了能够触发规则的关联表达式的模式。<code>onMatch</code>方法生成了一个新的关联表达式并调用<a href="http://calcite.apache.org/apidocs/org/apache/calcite/plan/RelOptRuleCall.html#transformTo(org.apache.calcite.rel.RelNode)" target="_blank" rel="noopener"><code>RelOptRuleCall.transformTo()</code></a>方法来标明规则被成功触发。</p>
<h2 id="查询优化过程"><a href="#查询优化过程" class="headerlink" title="查询优化过程"></a>查询优化过程</h2><p>首先，calcite并没有按照规定的顺序去触发优化规则，查询优化会尝试分支树的很多分支，如果规则A和规则B都符合查询运算符树中的给定部分，calcite会同时触发他们。</p>
<p>然后 calcite会使用 ”成本“来筛选计划，但是成本模型并不会阻止Calcite短期内选择更加昂贵的规则.</p>
<p>很多优化器都会有一个线性优化方案。在面对选择规则A或者规则B时，如上所述，这样的优化器需要立即选择。一般的优化器可能会有这样的策略，例如”将规则A应用于整棵树，然后将规则B应用于整棵树”，或者基于成本的策略，使用成本更便宜的结果的规则。</p>
<p>其实这些做法是一种妥协，但是Calcite并没有这么做，这使得组合各种规则变得简单。如果你想要将规则组合在一起以识别具有规则的物化视图从而能够从csv或者jdbc源系统中读取数据的话，你只需要将Calcite设置为所有规则的集合并告知她即可。</p>
<p>Calcite使用了一个成本模型。这个成本模型决定哪个计划最终得到执行，并且有时候会对搜索树进行剪纸操作以防止搜索空间爆炸，但是它不会强制你在规则A还是B之间做出选择。这个非常重要，因为这能避免实际上并不是最佳的搜索空间中陷入局部极小值。</p>
<p>这个成本模型也是”可插拔”的，就像它基于的表和查询运算符统计一样。这个会在后面讲到。</p>
<h2 id="JDBC适配器"><a href="#JDBC适配器" class="headerlink" title="JDBC适配器"></a>JDBC适配器</h2><p>JDBC适配器将JDBC数据源中的schema映射为Calcite schema。下面是一个从MySQL “foodmart”数据库中读取数据的schema的例子：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#123;</span></span><br><span class="line">  <span class="attr">version:</span> <span class="string">'1.0'</span><span class="string">,</span></span><br><span class="line">  <span class="attr">defaultSchema:</span> <span class="string">'FOODMART'</span><span class="string">,</span></span><br><span class="line">  <span class="attr">schemas:</span> <span class="string">[</span></span><br><span class="line">    <span class="string">&#123;</span></span><br><span class="line">      <span class="attr">name:</span> <span class="string">'FOODMART'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">'custom'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">factory:</span> <span class="string">'org.apache.calcite.adapter.jdbc.JdbcSchema$Factory'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">operand:</span> <span class="string">&#123;</span></span><br><span class="line">        <span class="attr">jdbcDriver:</span> <span class="string">'com.mysql.jdbc.Driver'</span><span class="string">,</span></span><br><span class="line">        <span class="attr">jdbcUrl:</span> <span class="string">'jdbc:mysql://localhost/foodmart'</span><span class="string">,</span></span><br><span class="line">        <span class="attr">jdbcUser:</span> <span class="string">'foodmart'</span><span class="string">,</span></span><br><span class="line">        <span class="attr">jdbcPassword:</span> <span class="string">'foodmart'</span></span><br><span class="line">      <span class="string">&#125;</span></span><br><span class="line">    <span class="string">&#125;</span></span><br><span class="line">  <span class="string">]</span></span><br><span class="line"><span class="string">&#125;</span></span><br></pre></td></tr></table></figure>

<p><strong>目前的限制：</strong>JDBC适配器目前只能下推表扫描的操作；所有的其他的操作（过滤，链接，聚合等等）都没有发生在Calcite中。我们的目标是将尽可能多的操作压缩到源系统中，随时随地的翻译语法、数据类型和内置函数。如果Calcite查询是建立在单一的JDBC数据库中的表上，原则上整个查询应该都转到数据库中执行。如果数据表是来自于多个JDBC源，或者是JDBC和非JDBC的混合源，Calcite将使用最有效的分布式查询方法。</p>
<h2 id="克隆JDBC适配器"><a href="#克隆JDBC适配器" class="headerlink" title="克隆JDBC适配器"></a>克隆JDBC适配器</h2><p>克隆的JDBC适配器将创建一个混合的数据库。这些数据是来自于JDBC数据库，但是每张表第一次被访问时，会被读进内存中。Calcite会基于这些内存表来进行评估查询，实际上是数据库的缓存。</p>
<p>下面的模型从MySQL中的”foodmart”库中读取表：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#123;</span></span><br><span class="line">  <span class="attr">version:</span> <span class="string">'1.0'</span><span class="string">,</span></span><br><span class="line">  <span class="attr">defaultSchema:</span> <span class="string">'FOODMART_CLONE'</span><span class="string">,</span></span><br><span class="line">  <span class="attr">schemas:</span> <span class="string">[</span></span><br><span class="line">    <span class="string">&#123;</span></span><br><span class="line">      <span class="attr">name:</span> <span class="string">'FOODMART_CLONE'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">'custom'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">factory:</span> <span class="string">'org.apache.calcite.adapter.clone.CloneSchema$Factory'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">operand:</span> <span class="string">&#123;</span></span><br><span class="line">        <span class="attr">jdbcDriver:</span> <span class="string">'com.mysql.jdbc.Driver'</span><span class="string">,</span></span><br><span class="line">        <span class="attr">jdbcUrl:</span> <span class="string">'jdbc:mysql://localhost/foodmart'</span><span class="string">,</span></span><br><span class="line">        <span class="attr">jdbcUser:</span> <span class="string">'foodmart'</span><span class="string">,</span></span><br><span class="line">        <span class="attr">jdbcPassword:</span> <span class="string">'foodmart'</span></span><br><span class="line">      <span class="string">&#125;</span></span><br><span class="line">    <span class="string">&#125;</span></span><br><span class="line">  <span class="string">]</span></span><br><span class="line"><span class="string">&#125;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>另一种技术是在现有的schema之上构建一个克隆模型。你可以使用source属性来引用模型中早先定义的schema，就像下面的例子：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#123;</span></span><br><span class="line">  <span class="attr">version:</span> <span class="string">'1.0'</span><span class="string">,</span></span><br><span class="line">  <span class="attr">defaultSchema:</span> <span class="string">'FOODMART_CLONE'</span><span class="string">,</span></span><br><span class="line">  <span class="attr">schemas:</span> <span class="string">[</span></span><br><span class="line">    <span class="string">&#123;</span></span><br><span class="line">      <span class="attr">name:</span> <span class="string">'FOODMART'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">'custom'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">factory:</span> <span class="string">'org.apache.calcite.adapter.jdbc.JdbcSchema$Factory'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">operand:</span> <span class="string">&#123;</span></span><br><span class="line">        <span class="attr">jdbcDriver:</span> <span class="string">'com.mysql.jdbc.Driver'</span><span class="string">,</span></span><br><span class="line">        <span class="attr">jdbcUrl:</span> <span class="string">'jdbc:mysql://localhost/foodmart'</span><span class="string">,</span></span><br><span class="line">        <span class="attr">jdbcUser:</span> <span class="string">'foodmart'</span><span class="string">,</span></span><br><span class="line">        <span class="attr">jdbcPassword:</span> <span class="string">'foodmart'</span></span><br><span class="line">      <span class="string">&#125;</span></span><br><span class="line">    <span class="string">&#125;,</span></span><br><span class="line">    <span class="string">&#123;</span></span><br><span class="line">      <span class="attr">name:</span> <span class="string">'FOODMART_CLONE'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">'custom'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">factory:</span> <span class="string">'org.apache.calcite.adapter.clone.CloneSchema$Factory'</span><span class="string">,</span></span><br><span class="line">      <span class="attr">operand:</span> <span class="string">&#123;</span></span><br><span class="line">        <span class="attr">source:</span> <span class="string">'FOODMART'</span></span><br><span class="line">      <span class="string">&#125;</span></span><br><span class="line">    <span class="string">&#125;</span></span><br><span class="line">  <span class="string">]</span></span><br><span class="line"><span class="string">&#125;</span></span><br></pre></td></tr></table></figure>

<p>你可以使用这种方式基于任何类型的schema创建一个克隆的schema，不仅仅是JDBC。</p>
<p>目前的系统中克隆的适配器功能不是所有的也不是最终的。我们计划开发更多的更复杂的缓存策略，以及更完整更有效的内存表的实现，但是现有的克隆的JDBC适配器像我们展示了有哪些功能我们可以用，并允许我们根据这些功能做出自己的尝试开发。</p>
<h3 id="更多的主题"><a href="#更多的主题" class="headerlink" title="更多的主题"></a>更多的主题</h3><p>有很多你的其他的方式来扩展Calcite而不仅仅是在这节中所介绍的这些方法。<a href="http://calcite.apache.org/docs/adapter.html" target="_blank" rel="noopener">adapter specification</a> 介绍了包含的APIs。</p>

    </div>

    
    
    

      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/calcite/" rel="tag"><i class="fa fa-tag"></i> calcite</a>
              <a href="/tags/SQL/" rel="tag"><i class="fa fa-tag"></i> SQL</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2020/03/18/calcite%E6%95%99%E7%A8%8B01-calcite%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5/" rel="prev" title="calcite教程01-calcite的基本概念">
      <i class="fa fa-chevron-left"></i> calcite教程01-calcite的基本概念
    </a></div>
      <div class="post-nav-item">
    <a href="/2020/03/18/calcite%E6%95%99%E7%A8%8B03-calcite%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%AE%9A%E4%B9%89SQL/" rel="next" title="calcite教程03-calcite实现自定义SQL">
      calcite教程03-calcite实现自定义SQL <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  
<div>
    
    <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;">-------------　　　　本文结束　<i class="fa fa-heart"></i>　感谢您的阅读　　　　-------------</div>
    
</div>


    
 </div>

  </div>


          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#下载安装"><span class="nav-number">1.</span> <span class="nav-text">下载安装</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#开始"><span class="nav-number">2.</span> <span class="nav-text">开始</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#模式发现："><span class="nav-number">3.</span> <span class="nav-text">模式发现：</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#schemas中的Tables和views"><span class="nav-number">4.</span> <span class="nav-text">schemas中的Tables和views</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#执行计划优化查询"><span class="nav-number">5.</span> <span class="nav-text">执行计划优化查询</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#查询优化过程"><span class="nav-number">6.</span> <span class="nav-text">查询优化过程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#JDBC适配器"><span class="nav-number">7.</span> <span class="nav-text">JDBC适配器</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#克隆JDBC适配器"><span class="nav-number">8.</span> <span class="nav-text">克隆JDBC适配器</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#更多的主题"><span class="nav-number">8.1.</span> <span class="nav-text">更多的主题</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="李喜延"
      src="https://tva1.sinaimg.cn/large/00831rSTly1gcyel996b4j30oa0oc1kx.jpg">
  <p class="site-author-name" itemprop="name">李喜延</p>
  <div class="site-description" itemprop="description">愿世界和平</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">25</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">4</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">25</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">李喜延</span>
</div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
  <script src="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

</body>
</html>
